//类
class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
  greet() {
    return 'hello' + this.greeting;
  }
}
let greeter = new Greeter('TypeScript');
//继承 派生类Dog通常被称作 子类，基类Animal通常被称作 超类。
// class Animal {
//   move(distanceInMeters: number = 0) {
//     console.log(`Animal move ${distanceInMeters}m.`);
//   }
// }
// class Dog extends Animal {
//   bark() {
//     console.log('woof woof!');
//   }
// }
// let dog = new Dog();
// dog.bark();
// dog.move(10);
//与前一个例子的不同点是，派生类包含了一个构造函数，它 必须调用 super()，它会执行基类的构造函数。
class Animal {
  name: string;
  constructor(theName) {
    this.name = theName;
  }
  move(distanceInMeters: number = 0) {
    console.log(`Animal move ${distanceInMeters}m.`);
  }
}
class Snake extends Animal {
  constructor(name: string) {
    super(name);
  }
  move(distanceInMeters: number = 23) {
    console.log('slithering-----');
    super.move(distanceInMeters);// 重写了父类的方法
  }
}
class Horse extends Animal {
  constructor(name: string) {
    super(name);
  }
  move(distanceInMeters = 100) {
    console.log('galloping-----');
    super.move(distanceInMeters);
  }
}
let sam = new Snake('python');
let tom: Animal = new Horse('palomino');
sam.move();
tom.move(454);
/**
 * 修饰符 公共，私有，受保护的 
 */
//默认为public
class Pub {
  public name: string;
}
//理解private
class Pri {
  private name: string;
  constructor(theName: string) {
    this.name = theName;
  }
}
class Rhino extends Pri {
  constructor() {
    super('Rhino');
  }
}
class Employee {
  private name: string;
  constructor(theName: string) {
    this.name = theName;
  }
}
let pri = new Pri('Goat');
let rhino = new Rhino();
let employee = new Employee('bob');
pri = rhino;
//pri = employee; // 报错：不能将类型“Employee”分配给类型“Pri”。类型具有私有属性“name”的单独声明。
//理解protected
class Persion {
  protected name: string;
  constructor(name: string) {
    this.name = name;
  }
}
class Staff extends Persion {
  constructor(name: string) {
    super(name);
  }
}
let xiaoming = new Staff('xiaoming'); // 可以通过实例方法访问name
//xiaoming.name;//报错：属性“name”受保护，只能在类“Persion”及其子类中访问。
class Pro {
  protected name: string;
  protected constructor(name: string) { // 可以被子类访问，但是不能在外面被实例化
    this.name = name;
  }
}
/**
 * readonly修饰符  读属性必须在声明时或构造函数里被初始化。
 */
class Octopus {
  readonly name: string;
  readonly numberOfLegs: number = 8;
  constructor(name: string) {
    this.name = name;
  }
}
let dad = new Octopus('man with the 8 strong legs');
//dad.name = 'man with the 8 strong legs';// 报错：无法分配到“name”，因为它是常数或只读属性。
/**
 * 参数属性 改造上面的Animal例子
 */
class PraAttr {
  constructor(private name: string) {

  }// 注意蓝是如何将声明和赋值合并在一起的
  move(distanceInMeters: number = 0) {
    console.log(`${name} move ${distanceInMeters}m.`);
  }
}
/**
 * 存取器
 */
let passcode = "secret passcode";
class People {
  private _fullName: string;
  get FullName(): string {
    return this._fullName;
  }
  set fullName(newName: string) {
    if (passcode && passcode == 'secret  passcode') {
      this._fullName = newName;
    } else {
      console.log("Error: Unauthorized update of employee!");
    }
  }
}
let people = new People();
people.fullName = 'kangkang';
/**
 * 静态属性/方法
 * 静态方法是类方法，不需要去实例化类就可以调用这个方法。
 * 静态方法在执行的时候就会分配内存，所以说直接用类名“.”方法名进行调用。非静态方法则需要声明一个对象进行调用。
 */
class Grid {
  static origin = { x: 0, y: 0 }; // 这里的origin可以通过Grid直接调用
  calcDisFromOri(point: { x: number, y: number }) {
    const xDis = point.x - Grid.origin.x;
    const yDis = point.y - Grid.origin.y;
    return (xDis * xDis - yDis * yDis) / this.scale;
  }
  constructor(public scale: number) { }
}
let grid = new Grid(5.0);
grid.calcDisFromOri({ x: 10, y: 10 });
/**
 * 抽象类
 * 不同于接口的是：抽象类中的方法不一定都要被实现
 */
abstract class Department {
  constructor(public name: string) {

  }
  printName(): void {
    console.log('Department name: ' + this.name);
  }
  abstract printMeeting(): void; // 必须在派生类中实现
}
class AccountingDepartment extends Department {
  constructor() {
    super('Accounting and Auditing'); // 在派生类的构造函数中必须调用 super()
  }
  printMeeting(): void {
    console.log('The Accounting Department meets each Monday at 10am.');
  }
  generateReports(): void {
    console.log('Generating accounting reports...');
  }
}
let department: Department; // 允许创建一个对抽象类型的引用
//department = new Department(); // 错误: 不能创建一个抽象类的实例
department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
//department.generateReports(); // 错误: 方法在声明的抽象类中不存在
